Introduction

visutils uses R basic graphics to visualize visium data in vareity of ways. The Main plotting function is plotVisium.

Install package

#devtools::install_github("iaaka/visutils")
library(visutils)
library(Seurat)
## Warning: package 'Seurat' was built under R version 4.0.5
## Attaching SeuratObject
## Attaching sp

Download public dataset from 10x web site

loadVisiumFrom10x("https://cf.10xgenomics.com/samples/spatial-exp/1.3.0","Visium_Mouse_Olfactory_Bulb",outdir="data")
mob = Load10X_Spatial('data/Visium_Mouse_Olfactory_Bulb/')

Plot visium

Categorical varible

Lets loa clustering information from just downloaded spaceranger output

cl = read.csv('data/Visium_Mouse_Olfactory_Bulb/analysis/clustering/graphclust/clusters.csv',row.names = 1)
mob$clusters = as.character(cl[colnames(mob),1])
table(mob$clusters,useNA = 'always')
## 
##    1    2    3    4    5    6    7 <NA> 
##  262  185  172  161  153  131  121    0
plotVisium(mob,z = mob$clusters)

## Quantitative variable

plotVisium(mob,z = mob$nCount_Spatial)

Lets explore the parameters

par(mar=c(0,0,1,6),bty='n')
plotVisium(mob,z = mob$nCount_Spatial,
          zfun = log1p, # log scale
          z2col = function(x)num2col(x,col = c('black','gray','orange','red')), # change colors
          cex = scaleTo(log1p(mob$nCount_Spatial)),                             # spot size it proportional to log1p of coverage
          legend.args = list(title='UMIs')                                      # set legend title  
          )

Control H&E appearance

Visualization of visium on top of H&E image internally performed by plotVisiumImg, plotVisium passes arguments to it. Check manual of plotVisiumImg to get more control over plotting

par(mar=c(0,0,1,6),bty='n')
plotVisium(mob,z = mob$nCount_Spatial,
          zfun = log1p, # log scale
          z2col = function(x)num2col(x,col = c('black','gray','orange','red')), # change colors
          cex = scaleTo(log1p(mob$nCount_Spatial)),                             # spot size it proportional to log1p of coverage
          zlim= c(500,2e4),                                                     # specify limits of value shown by color, all values outside of the range will be trimmed to the range
          legend.args = list(title='UMIs'),                                     # set legend title  
          he.grayscale = TRUE,                                                  # show H&E image in grayscale
          img.alpha = 0.5,                                                      # make H&E image semi-transparent
          he.img.width = 400                                                    # reduce resolution of H&E image (helps to reduce file size when saving to pdf)
          )
## Loading required package: EBImage

If you need H&E only

par(mar=c(0,0,1,6),bty='n')
plotVisium(mob,cex=0)

Multiple genes (or celltypes)

There are two ways to show multiple variable (for example genes): pie plots or mean colors. Lets first find genes to be shown.

mob = NormalizeData(mob)
Idents(mob) = "clusters"
markers = FindAllMarkers(mob)
## Calculating cluster 1
## Calculating cluster 7
## Calculating cluster 4
## Calculating cluster 5
## Calculating cluster 3
## Calculating cluster 6
## Calculating cluster 2
markers[1:5,]
##                 p_val avg_log2FC pct.1 pct.2     p_val_adj cluster    gene
## Gm42418 5.235306e-114   2.146382 0.981 1.000 1.690219e-109       1 Gm42418
## Ptgds   8.944307e-113   3.784747 0.996 0.987 2.887670e-108       1   Ptgds
## Fabp7    2.799721e-93   2.249930 0.966 0.993  9.038901e-89       1   Fabp7
## Apod     1.207440e-91   2.644788 0.947 0.922  3.898220e-87       1    Apod
## Apoe     3.684006e-90   1.322135 0.996 1.000  1.189381e-85       1    Apoe

Lets select one genes per cluster

m = markers[markers$pct.1-markers$pct.2 > 0.3,]
m = do.call(rbind,lapply(split(m,m$cluster),function(x)x[order(x$avg_log2FC,decreasing = TRUE)[1],]))
m = m[order(as.character(m$cluster)),]
m
##          p_val avg_log2FC pct.1 pct.2    p_val_adj cluster   gene
## 1 2.528823e-54  1.8989167 0.645 0.264 8.164305e-50       1    Omp
## 2 4.888868e-31  0.8058507 0.595 0.239 1.578371e-26       2    Vip
## 3 1.594457e-79  1.5089431 0.953 0.288 5.147706e-75       3 Ly6g6e
## 4 3.374414e-53  1.0385090 1.000 0.660 1.089429e-48       4  Ptk2b
## 5 2.698230e-77  1.6047715 1.000 0.609 8.711235e-73       5   Penk
## 6 4.930226e-34  0.9884102 0.870 0.485 1.591723e-29       6   Lcat
## 7 2.710175e-62  1.3021307 0.950 0.349 8.749801e-58       7 Shisa3
par(mfrow=c(2,4),mar=c(0,0,1,0),bty='n')
for(gid in m$gene)
  plotVisium(mob,mob@assays$Spatial@data[gid,],main=gid,plot.legend = FALSE)

Mean color

# select genes to be plotted, matrix should be cell-by-gene, so lets transpose it
exps = t(as.matrix(mob@assays$Spatial@data[m$gene,]))
cols = RColorBrewer::brewer.pal(nrow(m),'Set1')
par(mfrow=c(1,2),mar=c(0,0,1,10),bty='n')
plotVisiumMultyColours(mob,exps,
                       cols = cols,
                       zfun = function(x)x^2,     # kernel to transform gene expression. Higher powers will give more sharp figure (each spot will be dominated by single cell type)
                       mode = 'mean',             # colors are averaged not overlayed (in this mode gene order makes no difference)
                       legend.ncol = 2,           # show legend in two columns
                       he.grayscale = TRUE,       # show H&E in grayscale
                       min.opacity = 255,         # be default total cell density is shown by opacity, set min.opacity to max (255) to disable it.
                       bg = '#00000000',          # set transparent background, so spots where neither of genes is expressed will be invisible 
                       main='Kernel x^2'
)
# make it sharper (the only difference is zfun)
plotVisiumMultyColours(mob,exps,
                       cols = cols,
                       zfun = function(x)x^6,     # kernel to transform gene expression. Higher powers will give more sharp figure (each spot will be dominated by single cell type)
                       mode = 'mean',             # colors are averaged not overlayed (in this mode gene order makes no difference)
                       legend.ncol = 2,           # show legend in two columns
                       he.grayscale = TRUE,       # show H&E in grayscale
                       min.opacity = 255,         # be default total cell density is shown by opacity, set min.opacity to max (255) to disable it.
                       bg = '#00000000',          # set transparent background, so spots where neither of genes is expressed will be invisible 
                       main='Kernel x^6'
)

Seven genes looks too many here to show them clearly all because some of them overlap.

IMPORTANT! By default each cell types is scaled individually so genes with high and low expression contributes equally to the plot. Use scale.per.colour = FALSE to disable it.

Pies

Usually pies are more confusing than mean colors, however in this case it allows to show overlapping Ptj2b/Penk and Lcat/Ly6g6e

par(mar=c(0,0,1,10),bty='n')
plotVisium(mob,pie.fracs=exps,
                       pie.cols = cols,
                       he.grayscale = TRUE,       # show H&E in grayscale
)
legend(grconvertX(1,'npc','user'),grconvertY(1,'npc','user'),fill=cols,legend = paste0(m$gene,' (cl',m$cluster,')'),xpd=TRUE)